package org.xx.armory.commons;

import java.util.Calendar;
import java.util.Date;

import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;
import static org.apache.commons.lang3.time.DateUtils.ceiling;
import static org.apache.commons.lang3.time.DateUtils.truncate;

public final class RequestUtils {
    private RequestUtils() {
        throw new AssertionError();
    }

    /**
     * 将多个部分组合为URL的路径。
     *
     * @param first
     *         第一个部分。
     * @param more
     *         其它部分。
     * @return 组合结果。
     */
    public static String joinURLPath(
            String first,
            String... more
    ) {
        final StringBuilder result = new StringBuilder();

        first = trimToEmpty(first);
        if (!first.isEmpty()) {
            result.append(first);
        }

        if (more != null) {
            for (String s : more) {
                s = trimToEmpty(s);
                if (s.startsWith("/")) {
                    s = s.substring(1);
                }
                if (s.isEmpty()) {
                    continue;
                }

                if (result.charAt(result.length() - 1) != '/') {
                    result.append('/');
                }

                result.append(s);
            }
        }

        return result.toString();
    }

    public static byte toByte(
            int b
    ) {
        if (b > 0xff || b < 0) {
            throw new IllegalArgumentException("illegal byte " + b + ", should between 0 and 255");
        } else if (b > 0x7f) {
            return (byte) (b & 0x0ff - 0x100);
        } else {
            return (byte) b;
        }
    }

    public static byte[] toByteArray(
            int[] ba
    ) {
        if (ba == null) {
            return null;
        }

        final byte[] result = new byte[ba.length];

        for (int i = 0; i < ba.length; ++i) {
            result[i] = toByte(ba[i]);
        }

        return result;
    }

    /**
     * 输出字节数组的内容。
     *
     * @param bytes
     *         待输出的字节数组。
     * @return 字节数组的内容，非打印字符被转化为十六进制格式。
     */
    public static String dumpBytes(
            byte[] bytes
    ) {
        if (bytes == null) {
            return "";
        }

        final StringBuilder result = new StringBuilder();

        for (final byte b : bytes) {
            if (b < 0x20) {
                result.append("\\x");
                final String hex = Integer.toHexString(b & 0x0FF);
                if (hex.length() == 1) {
                    result.append("0");
                }
                result.append(hex);
            } else {
                result.append((char) b);
            }
        }

        return result.toString();
    }

    /**
     * 输出字符串的内容。
     *
     * @param s
     *         待输出的字符串。
     * @return 字符串的内容，非打印字符被转化为十六进制格式。
     */
    public static String dumpString(
            String s
    ) {
        if (s == null) {
            return "";
        }

        final StringBuilder result = new StringBuilder();

        for (int i = 0; i < s.length(); ++i) {
            final char ch = s.charAt(i);
            if (ch < 0x20 || ch > 0x7f) {
                result.append("\\u");
                final String hex = Integer.toHexString(ch & 0xFFFF);
                if (hex.length() == 1) {
                    result.append("000");
                } else if (hex.length() == 2) {
                    result.append("00");
                } else if (hex.length() == 3) {
                    result.append("0");
                }
                result.append(hex);
            } else {
                result.append(ch);
            }
        }

        return result.toString();
    }

    /**
     * 修正SpringMvc的URI编码问题。
     * <p>SpringMvc强制使用ISO-8859-1编码来解码URL，所以需要再转换为UTF_8。</p>
     *
     * @param src
     *         原始字符串（使用ISO8859-1编码）。
     * @return 按照UTF_8解码的字符串。
     */
    public static String fixSpringMvcUrlEncoding(
            String src
    ) {
        if (src == null) {
            throw new IllegalArgumentException("src cannot be null");
        }

        return new String(src.getBytes(ISO_8859_1), UTF_8);
    }

    /**
     * 调整起始日期。
     * <p>如果参数{@code p}不是{@code null}，那么调整到该日期表示的这一日的起始时刻。比如 {@literal 2017/06/01 23:24:25} 被会调整为 {@literal 2017/06/01 00:00:00}</p>
     *
     * @param d
     *         待调整的日期。
     * @return 调整结果。
     */
    public static Date fixStartDate(
            Date d
    ) {
        if (d != null) {
            return truncate(d, Calendar.DAY_OF_MONTH);
        } else {
            return null;
        }
    }

    /**
     * 调整起始日期。
     * <p>如果参数{@code p}不是{@code null}，那么调整到该日期表示的这一日的结束时刻。比如 {@literal 2017/06/01 23:24:25} 被会调整为 {@literal 2017/06/02 00:00:00}</p>
     *
     * @param d
     *         待调整的日期。
     * @return 调整结果。
     */
    public static Date fixEndDate(
            Date d
    ) {
        if (d != null) {
            return ceiling(d, Calendar.DAY_OF_MONTH);
        } else {
            return null;
        }
    }
}
